import os.path
from urlparse import urlparse, urljoin
from weakref import WeakValueDictionary
from connection import connection_factory

class SchemeRegistry(object):
    def __init__(self):
        self.schemes = {}
        
    def register(self, type):
        self.schemes[type._scheme] = type
        
    def create_instance(self, url, child=None):
        if not isinstance(url, str) and not isinstance(url, BaseURL):
            raise ValueError()
        url = str(url)
        
        if child is not None:
            if not isinstance(child, str) and not isinstance(child, BaseURL):
                raise ValueError()
            child = str(child)
    
        scheme = urlparse(url, "path").scheme
    
        if scheme in self.schemes:
            return self.schemes[scheme](url, child)
        else:
            raise AttributeError("unknown scheme "+scheme)

class BaseURL(object):
    connections = {}
    
    def __init__(self, url, child=None):
        elements = urlparse(url)
        self._path = elements.path
        if child:
            self._path = os.path.join(self._path, child)
        self._connection = connection_factory.get_connection(self, self._connection_type)
        self._path = os.path.normpath(self._path)
        
        query = elements.query
        self.parameter = {}
        for parameter in query.split("&"):
            if len(parameter) > 0:
                parts = parameter.split("=")
                self.parameter[parts[0]] = parts[1]
        
    def _build_parameter_string(self):
        if len(self.parameter) == 0:
            return ""
        
        string = "?"
        for key, value in self.parameter.iteritems():
            string += key+"="+value+"&"
        return string[:-1] 
            
    def __div__(self, b):
        return URL(self, b)
    
    def __eq__(self, b):
        return str(self) == str(b)
    
    def get_path(self):
        return self._path
    
    def get_parent(self):
        return URL(self, "../")

    def get_scheme(self):
        return self._scheme
    
    def set_path(self, value):
        if value is None:
            self._path = ""
        else:
            self._path = os.path.normpath(value)
        
    def get_connection(self):
        if not self._connection.is_open():
            self._connection.open(self)
        return self._connection
        
    authority = None
    path = property(get_path, set_path)
    parent = property(get_parent)
    scheme = property(get_scheme)
    connection = property(get_connection)
    
class BaseRemoteURL(BaseURL):
    def __init__(self, url, child=None):
        elements = urlparse(url)
        self._authority = elements.netloc
        BaseURL.__init__(self, url, child)
        
    def __str__(self):
        if self._authority:
            return urljoin(self._scheme+"://"+self._authority, self._path)+self._build_parameter_string()
        else:
            return self._scheme+":"+self._path+self._build_parameter_string()

    def get_authority(self):
        return self._authority

    def get_hostname(self):
        return self._parse_authority()[2]

    def get_port(self):
        return self._parse_authority()[3]

    def get_username(self):
        return self._parse_authority()[0]

    def get_password(self):
        return self._parse_authority()[1]

    def set_authority(self, value):
        self._authority = value
        
    def set_hostname(self, value):
        parts = self._parse_authority()
        parts[2] = value
        self._safe_authority(parts)
        
    def set_port(self, value):
        parts = self._parse_authority()
        parts[3] = value
        self._safe_authority(parts)
        
    def set_username(self, value):
        parts = self._parse_authority()
        parts[0] = value
        self._safe_authority(parts)

    def set_password(self, value):
        parts = self._parse_authority()
        parts[1] = value
        self._safe_authority(parts)

    def _parse_authority(self):
        if self._authority:
            parts = urlparse("//"+self._authority)
            if parts.port:
                port = int(parts.port)
            else:
                port = None
            return [parts.username, parts.password, parts.hostname, port]
        else:
            return [None, None, None, None]
        
    def _safe_authority(self, parts):
        if parts[1]:
            if parts[0]:
                if parts[2]:
                    self._authority = parts[0]+":"+parts[1]+"@"+parts[2]
                else:
                    raise AttributeError("username and password are readonly until hostname is set")
            else:
                raise AttributeError("password is readonly until username is set")
        else:
            if parts[0]:
                if parts[2]:
                    self._authority = parts[0]+"@"+parts[2]
                else:
                    raise AttributeError("username and password are readonly until hostname is set")
            else:
                if parts[2]:
                    self._authority = parts[2]
                else:
                    self._authority = None
        if parts[3]:
            if self._authority:
                self._authority = self._authority+":"+str(parts[3])
            else:
                raise AttributeError("port readonly until hostname is set")   
    
    authority = property(get_authority, set_authority)
    hostname = property(get_hostname, set_hostname)
    port = property(get_port, set_port)
    username = property(get_username, set_username)
    password = property(get_password, set_password)

scheme_registry = SchemeRegistry()

def URL(url, child=None):
    return scheme_registry.create_instance(url, child)

import protocols
